﻿using System;
using System.IO;
using System.Text;
using System.Threading;

namespace Inovout.Data.Redis
{
    public class RedisCommandScript
    {

        internal RedisCommandResult CommandResult { get; set; }
        private static readonly byte[][] literalBuffers;
        private RedisLiteral literal;

        public RedisCommandParameter[] CommandParameters { get; private set; }
        static RedisCommandScript()
        {
            var literalArray = Enum.GetValues(typeof(RedisLiteral));
            literalBuffers = new byte[literalArray.Length][];
            foreach (RedisLiteral literal in literalArray)
            {
                literalBuffers[(int)literal] = Encoding.UTF8.GetBytes(literal.ToString().ToLower());
            }
        }
        public RedisCommand Command { get; private set; }
        internal RedisCommandScript(RedisCommand command, RedisLiteral literal, RedisCommandParameter arg)
            :this(command,literal,new RedisCommandParameter[]{arg})
        { 
        }
        internal RedisCommandScript(RedisCommand command, RedisLiteral literal, RedisCommandParameter[] args)
        {
            Command = command;
            this.literal = literal;
            CommandParameters = args;
        }
        public static RedisCommandScript Create<T>(RedisCommand command, RedisLiteral literal
            , RedisCommandParameter[] args,out RedisCommandResult<T> commandResult)
        {
            commandResult = new RedisCommandResult<T>(new RedisCommandScript(command, literal, args));
            return commandResult.CommandScript;
        }
        internal void Write(Stream stream)
        {
            RedisCommandParameter.WriteSymbol(stream, RedisCommandParameter.ArgumentCountSymbolBuffer
                , CommandParameters.Length + 1);

            WriteCommand(stream);
            foreach (var commandParameter in CommandParameters)
            {
                commandParameter.Write(stream);
            }
        }
        private void WriteCommand(Stream stream)
        {
            byte[] buffer = literalBuffers[(int)literal];

            RedisCommandParameter.WriteSymbol(stream, RedisCommandParameter.ArgumentLengthSymbolBuffer, buffer.Length);

            stream.Write(buffer, 0, buffer.Length);
            stream.Write(RedisCommandParameter.CrlfButffer, 0, RedisCommandParameter.CrlfButffer.Length);
        }
        public WaitHandle AsyncWaithHandler { get; private set; }
        internal void SetWaitHandler(WaitHandle asyncWaithHandler)
        {
            AsyncWaithHandler = asyncWaithHandler;
        }
    }
}
